package com.apps.java.javanote02;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class _23IO流_字节流 {
    /**
     * IO流
     * 一、概述
     * IO：输入/输出（input/Output）
     * 流：是一种抽象概念，是对数据传输的总称。也就是说数据在设备间的传输称为流，流的本质是数据传输
     * IO流就是用来处理设备间数据传输问题的：
     * 常见的应用：文本复制；文件上传；文件下载
     * <p>
     * 二、IO流的分类
     * 1.按照数据的流向：
     * （1）输入流：读数据
     * （2）输出流：写数据
     * 2.按照数据类型来分：
     * （1）字节流：
     * a.字节输入流
     * b.字节输出流
     * （2）字符流
     * a.字符输入流
     * b.字符输出流
     * 一般来说，我们对于IO流的分类是按照数据类型来分的
     * <p>
     * 三、IO流的使用
     * 1.如果数据通过Windows自带的记事本软件打开，我们还可以读懂里面的内容，就使用字符流；
     * 2.如果数据通过Windows自带的记事本软件打开，里面的内容是一堆乱码，就使用字节流；
     * 3.如果你不知道该使用哪一种类型的流，就使用字节流
     * <p>
     * 四、字节流写数据
     * 1.字节流抽象类：
     * （1）InputStream：	表示字节输入流的所有类的超类（父类）
     * （2）OutputStream：	表示字节数出流的所有类的超类（父类）
     * 子类名称特点：子类名称都是以父类名作为子类名的后缀
     * <p>
     * 2.FileOutputStream：文件输出流用于将数据写入File
     * FileOutputStream(String name)：创建文件输出流以指定的名称写入文件
     * FileOutputStream(File file)：创建文件输出流以指定的File对象表示的文件
     * <p>
     * 3.使用字节输出流写数据的步骤：
     * （1）创建字节输出流对象（调用系统功能创建了文件，创建字节输出流对象，让字节数出流对象指向文件）
     * （2）调用字节输出流对象的写数据方法
     * （3）释放资源（关闭此文件输出流并释放与此流相关的任何系统资源）
     * void close()
     * <p>
     * 4.字节流写数据的3钟方式
     * 方法名
     * void write(int b)						将指定的字节写入此文件输出流，一次写一个字节数据
     * void write(byte[] b)					将b.length字节从指定的字节数组写入此文件输出流，一次写一个字节数组数据
     * void write(byte[] b,int off, int len)	将len字节从指定的字节数组开始，从偏移量off开始写入此文件输出流，一次写一个字节数组的部分数据
     * <p>
     * 5.字节流写数据的两个小问题
     * （1）字节流写数据如何实现换行？
     * 写完数据后，加换行符
     * Windows：\r\n
     * Linux:	\n
     * mac:	\r
     * <p>
     * （2）字节流写数据如何实现追加写入？
     * public FileOutputStream(String name,boolean append)
     * 创建文件输出流以指定的名称写入文件，如果第二个参数为true，则字节将写入文件的末尾而不是开头
     * <p>
     * 6.字节流写数据加异常处理
     * finally：在异常处理时提供finally块来执行所有清除操作，比如说IO流中的释放资源
     * 被finally控制的语句一定会执行，除非JVM退出
     * <p>
     * 五、字节流读数据
     * 1.FileInputStream：从文件系统中的文件获取输入字节
     * FileInputStream(String name)：通过打开与实际文件的连接来创建一个FileInputStream，该文件由系统中的路径名name命名。
     * <p>
     * 2.使用字节流输入流读数据的步骤
     * （1）创建字节输入流对象
     * （2）调用字节输入流对象的读数据方法
     * （3）释放资源
     * <p>
     * 六、字节缓冲流
     * <p>
     * 1.字节缓冲流：
     * （1）BufferOutputStream：该类实现缓冲输出流。通过设置这样的输出流，应用程序可以向底层输出流写入字节，而不必为写入的每个字节导致底层系统的调用。
     * （2）BufferedInputStream：创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时，内部缓冲区将根据需要从所包含的输入流中重新填充，一次很多字节。
     * <p>
     * 2.构造方法
     * （1）字节缓冲输出流：BufferedOutputStream(OutputStream out)
     * （2）字节缓冲输入流：BufferedInputStream(InputStream in)
     * <p>
     * 为什么构造方法需要的是字节流，而不是具体的文件或者路径呢？
     * 字节缓冲刘仅仅是提供缓冲区，而真正的读写数据还是得依靠基本的字节流对象进行操作
     */

    public static void main(String[] args) throws Exception {
		/*
		//创建file对象
		File f = new File("E:\\Java\\IO流文章\\a.txt");
		//FileOutputStream(File file):创建文件输出流以指定的File对象表示的文件
		//FileOutputStream fileOut = new FileOutputStream(f);

		//FileOutputStream(String name):创建文件输出流以指定的名称写入文件
		FileOutputStream fileOut = null;
		try {
			fileOut = new FileOutputStream("E:\\Java\\IO流文章\\b.txt");
			/*
			 * 做了三件事：
			 * 	1.调用系统功能创建文件
			 * 	2.创建了字节输出流对象
			 * 	3.让字节输出流对象指向创建好的文件


			//void write (int b)：将指定的字节写入此文件输出流
			fileOut.write(65);

			//创建字节数组
			//byte[] num = {97,98,99,100,101};
			//byte[] getBytes()：返回字符串对应的字节数组
			byte[] num = "abcde".getBytes();

			//void write(byte[] b)将b.length字节从指定的字节数组写入此文件输出流
			fileOut.write(num);

			//void write(byte[] b,int off, int len)	将len字节从指定的字节数组开始，从偏移量off开始写入此文件输出流
			fileOut.write(num, 2,3);//索引为2开始，连续写3位

		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(fileOut != null){
			try {
				//void close()关闭此文件输出流并释放与其相关联的任何系统资源。
				fileOut.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			}
		}
		*/


        //写数据换行和追加数据

        //创建字节输出对象
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("E:\\Java\\IO流文章\\c.txt", true);

            //写数据
            for (int i = 0; i < 10; i++) {
                out.write("hello".getBytes());
                out.write("\r\n".getBytes());
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    //关闭资源
                    out.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

	/*
	//字节流读数据
		//创建字节输入流对象
		FileInputStream fileIn = new FileInputStream("E:\\Java\\IO流文章\\b.txt");

		//调用字节输入流对象的读数据方法
		//int read()：从该输入流读取一个字节的数据

		/*
		//第一次读取数据
		int read = fileIn.read();
		System.out.println("文件中的内容：" + read);
		System.out.println("强转后：" + (char)read);

		//第二次读取数据
		read = fileIn.read();
		System.out.println("文件中的内容：" + read);
		System.out.println("强转后：" + (char)read);
		*/

		/*
		//使用循环读取数据
		int by = fileIn.read();
		while( by != -1 ){
			System.out.println("文件中的内容：" + by);
			System.out.println("强转后：" + (char)by);
			by = fileIn.read();
		}
		/

		//优化程序
		int by;
		/*
		 * 1.fileIn.read()：读取数据
		 * 2.by = fileIn.read()：将读出的数据赋值给by
		 * 3.by != -1：判断读取到的数据是否是-1
		 *
		/
		while((by = fileIn.read()) != -1){
			System.out.print((char)by);
			by = fileIn.read();
		}

		//注意事项：如果文件达到末尾，会输出-1

		//释放资源
		fileIn.close();
	*/


        //字节缓冲流

		/*
		 *写数据
			//创建字节缓冲输出流：BufferedOutputStream(OutputStream out)
			BufferedOutputStream bou = new BufferedOutputStream(new FileOutputStream("E:\\java\\io\\a.txt"));

			//写数据
			bou.write("hello\r\n".getBytes());
			bou.write("world\r\n".getBytes());

			//释放资源
			bou.close();
		*/

        //读数据
          //创建字节缓冲输入流：BufferedInputStream(InputStream in)
        BufferedInputStream bin = new BufferedInputStream(new FileInputStream("E:\\java\\io\\a.txt"));

        //读数据
        //方式一：一次读取一个字节数据
        int by;
        while ((by = bin.read()) != -1) {
            System.out.print((char) by);
        }
    }
}